package com.egg.mall.service.sku.order.impl;

import cn.hutool.core.util.ObjectUtil;
import com.egg.basic.enums.pay.BusinessTypeEnum;
import com.egg.basic.fegin.BasicPayFeignClient;
import com.egg.basic.model.request.PayPost;
import com.egg.common.context.util.LocalThreadContextUtils;
import com.egg.common.core.exception.CustomException;
import com.egg.common.core.model.response.ResponseData;
import com.egg.common.mybatis.service.impl.BaseServiceImpl;
import com.egg.common.util.IdGenUtil;
import com.egg.common.util.JsonUtil;
import com.egg.mall.entity.sku.orders.SkuOrders;
import com.egg.mall.entity.sku.orders.SkuOrdersLinkSkuSnapshot;
import com.egg.mall.enums.OrderStateEnum;
import com.egg.mall.mapper.sku.order.SkuOrdersMapper;
import com.egg.mall.model.request.OrderPostOrPut;
import com.egg.mall.rabbitmq.sender.SkuOrderSender;
import com.egg.mall.service.sku.order.ISkuOrdersLinkSkuSnapshotService;
import com.egg.mall.service.sku.order.ISkuOrdersService;
import com.egg.mall.service.sku.order.ISkuOrdersStateHistoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;


/**
 * @author east
 * @since 2022-08-27
 */
@Slf4j
@Service
public class SkuOrdersServiceImpl extends BaseServiceImpl<SkuOrdersMapper, SkuOrders> implements ISkuOrdersService {


    @Autowired
    private ISkuOrdersStateHistoryService skuOrdersStateHistoryService;
    @Autowired
    private ISkuOrdersLinkSkuSnapshotService skuOrdersLinkSkuSnapshotService;
    @Autowired
    private BasicPayFeignClient basicPayFeignClient;
    @Autowired
    private SkuOrderSender skuOrderSender;


    /**
     * 订单新增并拉起支付
     *
     * @param add
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public String addAndPay(OrderPostOrPut add) {
        List<SkuOrdersLinkSkuSnapshot> skuOrdersLinkSkuSnapshotList = skuOrdersLinkSkuSnapshotService.buildOrderSku(add.getPayAmount(), add.getSkuList());
        if (ObjectUtil.isEmpty(skuOrdersLinkSkuSnapshotList)) {
            throw new CustomException("下单商品为空");
        }
        SkuOrders skuOrders = JsonUtil.objToObj(add, SkuOrders.class);
        skuOrders.setUserId(LocalThreadContextUtils.getUserId());
        skuOrders.setOrdersNo(IdGenUtil.serialId());
        skuOrders.setState(OrderStateEnum.PAY_WAIT.getCode());
        baseSave(skuOrders);
        skuOrdersStateHistoryService.add(skuOrders.getId(), skuOrders.getState());
        skuOrdersLinkSkuSnapshotList.forEach(o -> o.setOrderId(skuOrders.getId()));
        skuOrdersLinkSkuSnapshotService.baseAdd(skuOrdersLinkSkuSnapshotList);
        String pay = pay(skuOrders, add.getPayType(), add.getClientType());
        skuOrderSender.orderDelayCancel(skuOrders.getId());
        return pay;
    }

    /**
     * 拉起支付
     *
     * @param orderId    订单ID
     * @param payType    支付类型
     * @param clientType 客户端类型
     * @return
     */
    @Override
    public String pay(Serializable orderId, String payType, String clientType) {
        SkuOrders skuOrders = baseGetById(orderId);
        return pay(skuOrders, payType, clientType);
    }

    /**
     * 拉起支付
     *
     * @param skuOrders  订单
     * @param payType    支付类型
     * @param clientType 客户端类型
     * @return
     */
    @Override
    public String pay(SkuOrders skuOrders, String payType, String clientType) {
        if (!Objects.equals(skuOrders.getState(), OrderStateEnum.PAY_WAIT.getCode())) {
            throw new CustomException("订单状态必须为[待支付]");
        }
        PayPost payPost = new PayPost();
        payPost.setPayType(payType);
        payPost.setClientType(clientType);
        payPost.setBusinessType(BusinessTypeEnum.MALL_SKU_ORDER.getCode());
        payPost.setBusinessId(skuOrders.getId().toString());
        payPost.setUserId(LocalThreadContextUtils.getUserId());
        payPost.setAmount(skuOrders.getTotalAmount());
        payPost.setSubject(skuOrders.getOrdersNo());
        ResponseData<String> payRd = basicPayFeignClient.pay(payPost);
        if (payRd.isError()) {
            throw new CustomException(payRd);
        }
        return payRd.getData();
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void timeout(Serializable orderId) {
        editState(orderId, OrderStateEnum.PAY_TIMEOUT);
        skuOrdersLinkSkuSnapshotService.resumeSkuStockByOrderId(orderId);
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void paySuccess(Serializable orderId) {
        editState(orderId, OrderStateEnum.PAY_FINISH);
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void editState(Serializable orderId, OrderStateEnum nextState) {
        int maxCount = 99;
        boolean jump;
        int initCount = 0;
        do {
            if (initCount > maxCount) {
                // 并发实在过高, 就丢弃一次统计
                log.warn("订单 {} 变更状态为 {} 并发过高", orderId, nextState.getMessage());
                throw new CustomException("修改订单状态并发过高");
            }
            SkuOrders orders = baseGetById(orderId);
            OrderStateEnum currentStatus = OrderStateEnum.getByCode(orders.getState());
            boolean canTransitionTo = currentStatus.canTransitionTo(nextState);
            if (!canTransitionTo) {
                log.warn("订单 {} 当前状态 {} 不允许变更为 {}", orderId, currentStatus.getMessage(), nextState.getMessage());
                return;
            }
            SkuOrders skuOrders = new SkuOrders();
            skuOrders.setId(orders.getId());
            skuOrders.setState(nextState.getCode());
            skuOrders.setVersion(orders.getVersion());
            jump = !baseEdit(skuOrders);
            initCount++;
        } while (jump);
        skuOrdersStateHistoryService.add(orderId, nextState.getCode());
    }


}
